﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Google.YouTube;
using System.Threading.Tasks;
using System.Net;
using System.IO;

namespace YoutubeGetterV2
{
    /// <summary>
    /// Interaction logic for YoutubeControl.xaml
    /// </summary>
    public partial class YoutubeControl : UserControl
    {
        public YoutubeControl()
        {
            InitializeComponent();
			thumbnail.DataContext = this;
        }

		#region properties
		public Boolean IsSelected { get; set; }
		public Video SelectedVideo
		{
			get { return (Video)GetValue(SelectedVideoProperty); }
			set { SetValue(SelectedVideoProperty, value); }
		}
		public static readonly DependencyProperty SelectedVideoProperty =
            DependencyProperty.Register("SelectedVideo", typeof(Video), typeof(YoutubeControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(ImageUpdated)));

		public BitmapImage DisplayImage
		{
			get { return (BitmapImage)GetValue(DisplayImageProperty); }
			set { SetValue(DisplayImageProperty, value); }
		}
		public static readonly DependencyProperty DisplayImageProperty =
            DependencyProperty.Register("DisplayImage", typeof(BitmapImage), typeof(YoutubeControl), new UIPropertyMetadata());

        public Boolean IsDownloading
        {
            get { return (Boolean)GetValue(IsDownloadingProperty); }
            set { SetValue(IsDownloadingProperty, value); }
        }
        public static readonly DependencyProperty IsDownloadingProperty =
            DependencyProperty.Register("IsDownloading", typeof(Boolean), typeof(YoutubeControl), new UIPropertyMetadata(false));

		public Int32 DownloadProgress
		{
			get { return (Int32)GetValue(DownloadProgressProperty); }
			set { SetValue(DownloadProgressProperty, value); }
		}
		public static readonly DependencyProperty DownloadProgressProperty =
			DependencyProperty.Register("DownloadProgress", typeof(Int32), typeof(YoutubeControl), new PropertyMetadata(0));



		public String ErrorMessage
		{
			get { return (String)GetValue(ErrorMessageProperty); }
			set { SetValue(ErrorMessageProperty, value); }
		}
		public static readonly DependencyProperty ErrorMessageProperty =
			DependencyProperty.Register("ErrorMessage", typeof(String), typeof(YoutubeControl), new PropertyMetadata(""));
		
		#endregion

		public void SetNewPicture(Video video)
		{
			DisplayImage = new BitmapImage();
			DisplayImage.BeginInit();
			DisplayImage.UriSource = new Uri(video.Thumbnails[0].Url);
			DisplayImage.EndInit();
		}

		public void StartDownload()
		{
			IsDownloading = true;
			YoutubeTools.currentDownloads++;
			Task task = new Task(new Action(() =>
			{
				VideoQuality quality = VideoQuality.MP4_1280x720;
				String downloadUrl = YoutubeTools.GetUrlFromVideoID(SelectedVideo.VideoId, quality);
				if (!String.IsNullOrEmpty(downloadUrl))
				{
					WebRequest request = WebRequest.Create(downloadUrl);
					WebResponse response = null;
					response = request.GetResponse();
					Stream videoStream = response.GetResponseStream();
					if (!Directory.Exists(YoutubeTools.downloadLocation))
					{
						Directory.CreateDirectory(YoutubeTools.downloadLocation);
					}
					String fullPath = String.Format(YoutubeTools.downloadLocation + "\\" + GenerateFileName(quality));
					if (!File.Exists(fullPath))
					{
						Stream fileStream = File.Create(fullPath);
						byte[] buffer = new byte[1024];
						Int32 bytesRead;
						Int32 totalBytesDownloaded = 0;
						try
						{
							do
							{
								bytesRead = videoStream.Read(buffer, 0, buffer.Length);
								fileStream.Write(buffer, 0, bytesRead);
								totalBytesDownloaded += bytesRead;
								Dispatcher.Invoke(new Action(() => DownloadProgress = (Int32)((float)totalBytesDownloaded / (float)response.ContentLength * 100)));
							} while (bytesRead > 0);
							videoStream.Close();
						}
						catch (Exception ex)
						{
							ErrorMessage = "Download error: " + ex.Message;
						}
						finally
						{
							YoutubeTools.currentDownloads--;
							IsDownloading = false;
							fileStream.Close();
						}
					}
					else
					{
						ErrorMessage = "File already exists. Skipped.";
						IsDownloading = false;
						YoutubeTools.currentDownloads--;
					}
				}
				else
				{
					YoutubeTools.currentDownloads--;
					IsDownloading = false;
					ErrorMessage = "Error: Could not locate file on the youtube servers";
				}
			}));
			task.Start();
		}

		private String GenerateFileName(VideoQuality quality = VideoQuality.Undefined)
		{
			String extension = "." + quality.ToString().Substring(0, 3).ToLower();
			if (extension.Contains("und"))
			{
				extension = "";
			}
			String filename = SelectedVideo.Title;
			String[] charsToReplace = new String[] { "\'", "\"", "?", "!", "\\", "/", ":", "*" };
			foreach (String character in charsToReplace)
			{
				filename = filename.Replace(character, "");
			}
			return filename + extension;
		}

		private static void ImageUpdated(DependencyObject property, DependencyPropertyChangedEventArgs args)
		{
			YoutubeControl control = property as YoutubeControl;
            control.SetNewPicture(args.NewValue as Video);
		}
    }

    public class VisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            String param = (String)parameter;
            Boolean visibility = (Boolean)value;
            if (param == "invert")
            {
                return visibility ? Visibility.Collapsed : Visibility.Visible;
            }
            else
            {
                return visibility ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            String param = (String)parameter;
            Visibility visibility = (Visibility)value;
            if (param == "invert")
            {
                return visibility == Visibility.Collapsed;
            }
            else
            {
                return visibility == Visibility.Visible;
            }
        }
    }
}
